#include <Connectivity/TCPConnection.hpp>

TCPConnection::TCPConnection(bool ipv6, int sock, struct sockaddr *socketaddr) {

	this->ipv6 = ipv6;
	this->sock = sock;
	this->socketaddr = socketaddr;
	this->connected = true;

	this->sendFlags = 0;
	this->recvFlags = 0;

//	struct timeval timeout;
//	timeout.tv_sec = 1;
//	timeout.tv_usec = 0;
//	setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
//	if(errno){
//		std::cout << "Error" << std::endl;
//	}

}

TCPConnection::~TCPConnection(){
	closeConnection();
}

int TCPConnection::sendData(void *data, size_t len) {

	if (connected) {

		size_t sendCount = 0;

		while (sendCount < len) {

			int returnCode = send(sock, (char*)data + sendCount, len - sendCount, sendFlags); //MSG_NOSIGNAL);


			if (returnCode > -1) {
				sendCount += returnCode;
			} else {
				closeConnection();
				break;
			}
		}

		return sendCount;
	}

	return -1;

}

int TCPConnection::receiveData(void *data, size_t len) {

	if (connected) {

		size_t recvCount = 0;

		while (recvCount < len) {

			int returnCode = recv(sock, (char*)data + recvCount, len - recvCount, recvFlags); //MSG_WAITALL);

			if (returnCode <= 0) {
				closeConnection();
				break;
			} else {
				recvCount += returnCode;
			}
		}
		return recvCount;
	}

	return -1;

}

void TCPConnection::getHostname(std::string &hostname){

	if(ipv6){

		sockaddr_in6 *ipv6In = (sockaddr_in6*)socketaddr;

		for(int i=0;i<16;i++){
			std::cout << std::hex << ipv6In->sin6_addr.__in6_u.__u6_addr8[i];
		}
		std::cout << std::endl;

	}else{

		sockaddr_in *ipv4In = (sockaddr_in*)socketaddr;

		uint8_t *addrRaw = (uint8_t*)&(ipv4In->sin_addr.s_addr);

		std::ostringstream oss;
		oss << (unsigned int)addrRaw[0] << ".";
		oss << (unsigned int)addrRaw[1] << ".";
		oss << (unsigned int)addrRaw[2] << ".";
		oss << (unsigned int)addrRaw[3];
		hostname = oss.str();

	}
}

bool TCPConnection::isConnected() {
	return connected;
}

void TCPConnection::closeConnection() {
	close(sock);
	connected = false;
}

void TCPConnection::setSendFlags(int sendFlags){
	this->sendFlags = sendFlags;
}

int TCPConnection::getSendFlags(){
	return sendFlags;
}

void TCPConnection::setRecvFlags(int recvFlags){
	this->recvFlags = recvFlags;
}

int TCPConnection::getRecvFlags(){
	return recvFlags;
}
